// wglapplayer.cpp
//

#include "config.h"
#include "wgl/wglapplayer.hpp"
#include "wgl/wglinstance.hpp"

using namespace wgl;

#include "wgl/wglapplayer.inl.cpp"



namespace wgl { AppLayerVTable _dummy_vtable{}; }

wgl::AppLayerVTable & WGL_API gl = _dummy_vtable;



AppLayerMaster *AppLayerMaster::current_master{nullptr};

std::vector<AppLayerLoader *>
AppLayerLoader::registered_loaders{1, nullptr};

std::unordered_map<std::string, AppLayerLoader *>
AppLayerLoader::registered_loaders_by_name{};

template<>
const AppLayerLoaderID AppLayerLoaderImpl<AppLayerLoaderDynamic>::LOADER_ID
= AppLayerLoader::register_loader<AppLayerLoaderDynamic>("WGL_LAYER_dynamic");



// AppLayerVTable::get_current_vtable
//
AppLayerVTable &AppLayerVTable::get_current_vtable ()
{
  WGL_ASSERT(AppLayerMaster::current_master);

  return AppLayerMaster::current_master->root_layer.vtable;
}



// AppLayerMaster::load
//
void AppLayerMaster::load ()
{
  if (loaded)
    return;
  loaded = true;

  WGL_TRACE("loading application layers");

  AppLayerLoader &loader = AppLayerLoader::get_loader(AppLayerLoaderDynamic::LOADER_ID);
  root_layer.loader_id = AppLayerLoaderDynamic::LOADER_ID;
  loader.load_layer(root_layer);

  Instance *instance = Instance::get_current_instance();
  WGL_ASSERT(instance);
  const std::vector<std::string> enabled_layers = instance->get_enabled_application_layers();
  for (const auto &it: enabled_layers)
    {
      WGL_TRACE(" - %s", it.c_str());
      AppLayerLoader &loader = AppLayerLoader::get_loader(it);
      loader.chain_layer(root_layer);
      root_layer.loader_id = loader.get_loader_id();
    }
  
  for (AppLayer *layer = &root_layer; layer; layer = layer->chain)
    {
      if (layers_by_id.size() <= layer->loader_id)
        layers_by_id.resize(layer->loader_id + 1, nullptr);
      layers_by_id[layer->loader_id] = layer;
    }
}



// AppLayerMaster::get_current_layer
//
AppLayer &AppLayerMaster::get_current_layer ( AppLayerLoaderID loader_id )
{
  WGL_ASSERT(current_master);
  WGL_ASSERT(loader_id > 0
             && loader_id < current_master->layers_by_id.size());
  WGL_ASSERT(current_master->layers_by_id[loader_id]);

  return *current_master->layers_by_id[loader_id];
}



// AppLayerMaster::reset
//
void AppLayerMaster::reset ()
{
  load();
}



// AppLayerMaster::make_current
//
void AppLayerMaster::make_current ()
{
  // // [FIXME] force manual unset current?
  // WGL_ASSERT(AppLayerMaster::current_master == nullptr
  //            || AppLayerMaster::current_master == this);

  if (AppLayerMaster::current_master != this)
    {
      AppLayerMaster::current_master = this;
      gl = root_layer.vtable;
    }
}



// AppLayerLoader::chain_layer
//
void AppLayerLoader::chain_layer ( AppLayer &layer )
{
  AppLayer *chain_layer = new AppLayer;

  WGL_ASSERT(layer.chain == nullptr);
  
  *chain_layer = layer;
  layer.chain = chain_layer;

  load_layer(layer);
}



// AppLayerLoaderDynamic::load_layer
//
void AppLayerLoaderDynamic::load_layer ( AppLayer &layer )
{
  DynamicLayerVTableLoader::load_vtable(layer.vtable);
}
